package main

import (
	"fmt"
	"strings"
)

// func f1(a string, b ...int) (sum int) {
// 	fmt.Println(b) //b是一个int的切片
// 	sum = 1 + 2
// 	return //上面已经声明这里可以省略
// }

func deferdemo() {
	fmt.Println("start")
	defer fmt.Println("1")
	defer fmt.Println("2")
	defer fmt.Println("3")
	fmt.Println("stop")
}
func f1() int {
	x := 5
	defer func() {
		x++ //修改的是x不是返回值
	}()
	return x
}

func f2() (x int) {
	defer func() {
		x++ //返回值是x
	}()
	return 5
}

func f3() (y int) {
	x := 5
	defer func() {
		x++ //修改的是x
	}()
	return x
}
func f4() (x int) {
	defer func(x int) {
		x++ //修改的是函数的副本
	}(x)
	return 5
}

//函数也可以作为参数类型
func f5(x func() int) {
	fmt.Println("123")
}

//函数也可以作为返回值
func f6(x func() int) func(int, int) int {

	return f7
}
func f7(x, y int) int {
	return 1 + 2
}

var f8 = func(x, y int) {
	fmt.Println(x + y)
}
var f10 = func(x, y int) {
	fmt.Println("this is f10")
	fmt.Println(x + y)
}

func f12(x func(int, int), m, n int) func() {
	tmp := func() {
		x(m, n)
	}
	return tmp
}
func addr(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}

}
func makeSuffixFunc(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}
func calc(base int) (func(int) int, func(int) int) {
	add := func(i int) int {
		base += i
		return base
	}

	sub := func(i int) int {
		base -= i
		return base
	}
	return add, sub
}
func calc1(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}
func funcA() {
	fmt.Println("func A")
}

func funcB() {
	defer func() {
		err := recover()
		//如果程序出出现了panic错误,可以通过recover恢复过来
		if err != nil {
			fmt.Println("recover in B")
		}
	}()
	panic("panic in B")
}

func funcC() {
	fmt.Println("func C")
}

func main() {
	// fmt.Println("函数defer ")
	// fmt.Println("函数 一段代码的封装,在")
	// f1("wujiangpan", 1, 2, 3, 45, 6, 7, 8, 9, 1, 2)
	//在命名函数中不可以再声明命名函数
	// fmt.Println("defer")
	// fmt.Println("defer处理函数结束之前释放资源，文件句柄，socket关闭，数据库关闭")
	deferdemo()
	//go语言的return不是原子操作，在底层分两步完成
	//第一步：赋值
	//第二部：真正的ret
	//defer就是在第一步和第二部之间执行
	fmt.Println(f1())
	fmt.Println(f2())
	fmt.Println(f3())
	fmt.Println(f4())
	fmt.Println("作用域：1，全局变量2.局部变量3.快变量")
	fmt.Println("函数类型")

	a1 := f1
	fmt.Printf("%T\n", a1)
	a2 := f5
	fmt.Printf("%T\n", a2)
	a3 := f6(f2)
	fmt.Printf("%T\n", a3)
	fmt.Println("匿名函数=没有名字的函数，函数内部不能声明带名字的函数")

	f9 := func(x, y int) {
		fmt.Println(x + y)
	}
	f9(10, 20)
	//如果只调用一次函数，可以简写为立即执行函数
	func(x, y int) {
		fmt.Println(x + y)
		fmt.Println("wujiangpan")
	}(200, 300)
	fmt.Println("闭包，是一个函数，包含了他外部作用域的一个变量")
	fmt.Println("底层原理：1.函数可以作为返回值 2，函数查找变量顺序，先在自己内部找，再在外面找；闭包=函数+外部变量的引用")
	//例子1
	res := f12(f10, 100, 200)
	res()
	//例子2
	res1 := addr(199)
	res2 := res1(299)
	fmt.Println(res2)

	jpgFunc := makeSuffixFunc(".jpg")
	txtFunc := makeSuffixFunc(".txt")
	fmt.Println(jpgFunc("test")) //test.jpg
	fmt.Println(txtFunc("test")) //test.txt

	f13, f14 := calc(10)
	fmt.Println(f13(1), f14(2)) //11 9
	fmt.Println(f13(3), f14(4)) //12 8
	fmt.Println(f13(5), f14(6)) //13 7
	fmt.Println("defer")
	x := 1
	y := 2
	defer calc1("AA", x, calc1("A", x, y))
	x = 10
	defer calc1("BB", x, calc1("B", x, y))
	y = 20
	fmt.Println("内置函数:close  关闭channel")
	fmt.Println("内置函数:len")
	fmt.Println("内置函数:new 分配内存 值类型  int struct")
	fmt.Println("内置函数:make 分配内存 引用类型 chan map slice")
	fmt.Println("内置函数:append 数组 slice ")
	fmt.Println("内置函数:painic/recover;没有异常处理，出现pannic用recover来恢复 使用panic/recover模式来处理错误。 panic可以在任何地方引发，但recover只有在defer调用的函数中有效")
	fmt.Println(`recover()必须搭配defer使用。defer一定要在可能引发panic的语句之前定义。`)

	funcA()
	funcB()
	funcC()

}
